﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Mbs.ComponentModel;
using System.Reflection;
using Mbs.Reflection;

namespace Mbs.Test.Undo
{
    [TestFixture]
    public class UndoActionTest3
    {

        class Employee : ComponentObject
        {
            private string name;
            private int age;

            public string Name
            {
                get { return name; }
                set
                {
                    if (!string.Equals(value, name))
                    {
                        var old = name;
                        name = value;
                        OnPropertyChanged("Name", value, old);
                    }
                }
            }

            public int Age
            {
                get { return age; }
                set
                {
                    if (value != age)
                    {
                        var old = age;
                        age = value;
                        OnPropertyChanged("Age", value, old);
                    }
                }
            }
        }

        class PropertyChangedAction : UndoAction
        {
            /// <summary>
            /// old value
            /// </summary>
            private PropertyItem[] _items;
            private object _target = null;


            public PropertyChangedAction(object target, string propetyName, object newValue, object oldValue)
                : this(target, new PropertyItem(target, propetyName, newValue, oldValue))
            {


            }

            public PropertyChangedAction(object target, params PropertyItem[] items)
            {
                _items = items;

                Name = string.Format("{0}.{1} propetry changed.", target.GetType().Name, _items[0].Name);
                _target = target;
            }

            /// <summary>
            /// undo
            /// </summary>
            public override void Undo()
            {
                foreach (PropertyItem item in _items)
                    _target.SetProperty(item.Name, item.OldValue, null);
            }

           

            /// <summary>
            /// redo
            /// </summary>
            public override void Redo()
            {
                foreach (PropertyItem item in _items)
                    _target.SetProperty(item.Name, item.NewValue, null);
            }
        }

        class PropertyItem
        {
            public object Target;
            public readonly string Name;
            public readonly object OldValue;
            public readonly object NewValue;


            public PropertyItem(string propetyName, object newValue, object oldValue)
            {
                NewValue = newValue;
                OldValue = oldValue;
                Name = propetyName;
            }

            public PropertyItem(object target, string propetyName, object newValue, object oldValue)
                : this(propetyName, newValue, oldValue)
            {
                Target = target;
            }
        }

        [Test]
        public void Test()
        {
            UndoManager undoMgr = new UndoManager();


            Employee emp = new Employee();
            emp.PropertyChanged += (s, e) =>
            {
                var e2 = e as Mbs.ComponentModel.PropertyChangedEventArgs;
                undoMgr.AddAction(new PropertyChangedAction(emp, e2.PropertyName, e2.NewValue, e2.OldValue));
            };

            Assert.IsNullOrEmpty(emp.Name);
            emp.Name = "ZhangSan";

            Assert.IsTrue(undoMgr.CanUndo);
            undoMgr.Undo();
            Assert.IsNullOrEmpty(emp.Name);

            undoMgr.Redo();
            Assert.IsTrue(string.Equals("ZhangSan", emp.Name));

            undoMgr.Clear();
            emp.BeginEdit();
            emp.Age = 18;
            Assert.IsTrue(emp.IsChanged);
            Assert.IsTrue(emp.IsEdit);
            Assert.IsFalse(undoMgr.CanUndo);
            emp.EndEdit();

            Assert.IsTrue(emp.IsChanged);
            Assert.IsFalse(emp.IsEdit);


            emp.AcceptChanges();
            Assert.IsFalse(emp.IsChanged);
        }

        
    }

}
